
local raw = ...
local setmetatable, getmetatable = raw.setmetatable, raw.getmetatable
local setfenv, getfenv = raw.setfenv, raw.getfenv
local create_key = raw.create_key
local type = type
local tostring = tostring
local error = error
local strbyte = string.byte
local strlower = string.lower

local key_meta do
	local key_getters = {
		down = raw.get_key_down;
		struck = raw.get_key_struck;
		released = raw.get_key_released;
	}
	key_meta = {
		__index = function(self,key)
			local getter = key_getters[key]
			if getter then
				return getter(self)
			end
			error('unrecognised field of key struct',2)
		end;
		__newindex = function()
			error('cannot modify key struct',2)
		end;
		__tostring = raw.get_key_summary;
	}
end

local keyboard_meta do
	local keycodes = {
	    up = 273, down = 274, right = 275, left = 276;
	    insert = 277, home = 278, ['end'] = 279;
	    pageup = 280, ['page up'] = 280;
	    pagedown = 281, ['page down'] = 281;
	    f1=282, f2=283, f3=284, f4=285, f5=286, f6=287, f8=289, f9=290, f10=291, f11=292, f12=293, f13=294, f14=295, f15=296;
	    numlock = 300, ['num lock'] = 300;
	    capslock = 301, ['caps lock'] = 301;
	    scrolllock = 302, ['scroll lock'] = 302;
	    rshift = 303,['right shift'] = 303;  lshift = 304,['left shift'] = 304;
	    rctrl = 305,['right ctrl'] = 305;    lctrl = 306,['left ctrl'] = 306;
	    ralt = 307,['right alt'] = 307;      lalt = 308,['left alt'] = 308;
	    backspace = 8, tab = 9,
	    esc = 27, escape = 27,
	    space = 32, spacebar = 32, ['space bar'] = 32,
	    enter = 13, ['return'] = 13
	}
	
	local keycodecache = setmetatable({}, {
	    __mode = 'kv';
	    __index = function(me,k)
	        local kobj = create_key(k)
			setmetatable(kobj, key_meta)
	        me[k] = kobj
	        return kobj
	    end;
	})	
	
	keyboard_meta = {
		__index = function(self,key)
			local keytype = type(key)
			if (keytype == 'number') then
				key = tostring(key)
			elseif (keytype ~= 'string') then
				return nil
			end
			key = strlower(key)
			local new_key
			if (#key == 1) then
				new_key = keycodecache[strbyte(key)]
			else
				key = keycodes[key]
				if (key == nil) then
					return nil
				end
				new_key = keycodecache[key]
			end
			self[key] = new_key
			return new_key
		end;
		
		__mode = 'kv';
	}
end

local key = {}

return setmetatable(key, keyboard_meta)